package com.triplelink.builder.query.evalueter;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Queue;

import com.triplelink.annotations.Property;
import com.triplelink.builder.query.QueryTL;
import com.triplelink.exception.TripleLinkException;
import com.triplelink.util.EntityUtil;

public class ObjectEvalueter
{
	public static void evaluete(Field field, Object currentEntity, String id, QueryTL query, Queue<Object> forDiscovery) throws IllegalArgumentException, IllegalAccessException
	{
		field.setAccessible(true);
		
		Property property = field.getAnnotation(Property.class);
		
		Object value = field.get(currentEntity);
		
		if (value == null)
			return;
		
		if (field.getType().isPrimitive())
		{
			throw new TripleLinkException(getAcceptTypeMsgException(field, property));
		}
		else if (value instanceof Collection)
		{
			Type type = field.getGenericType();
			
			if (type instanceof ParameterizedType && !((ParameterizedType) type).getActualTypeArguments()[0].getClass().isPrimitive())
			{
				for (Object obj : (Collection<?>) value)
					putTriple(id, property.uri(), obj, query, forDiscovery);
			}
			else
			{
				throw new TripleLinkException(getAcceptTypeMsgException(field, property));
			}
		}
		else if (field.getType().isArray())
		{
			for (Object obj : (Iterable<?>) value)
				putTriple(id, property.uri(), obj, query, forDiscovery);
		}
		else
		{
			putTriple(id, property.uri(), value, query, forDiscovery);
		}
	}
	
	private static void putTriple(String id, String uri, Object object, QueryTL query, Queue<Object> forDiscovery) throws IllegalArgumentException, IllegalAccessException
	{
		String objectId = EntityUtil.getIdOrCreate(object);
		
		query.appendUri(id, uri, objectId);
		
		if (!query.hasDicovered(objectId, object))
			forDiscovery.add(object);
	}
	
	private static String getAcceptTypeMsgException(Field field, Property property)
	{
		return field + ": the property " + property.uri() + " only acepets Entities with annotation @Id, or, Collection of them!";
	}
}